package client.redis.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONValidator;
import com.alibaba.fastjson.TypeReference;

import client.redis.IRedisClient;
import client.redis.RedisClientController;
import client.redis.RedisTreeNode;
import client.redis.impl.DO.RedisDBTreeNode;
import client.redis.impl.DO.RedisKeyTreeNode;
import client.redis.impl.DO.RedisRootTreeNode;
import core.AlertUtil;
import core.FormDialog;
import javafx.collections.FXCollections;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import redis.clients.jedis.ListPosition;
import redis.clients.jedis.Tuple;

/**
 * Redis客户端实现抽象类
 * @author self
 *
 */
public abstract class AbstractRedisClientImpl implements IRedisClient{

	/**
	 * redis key类型字符串常量
	 */
	protected static final String KEY_TYPE_STRING = "string";
	protected static final String KEY_TYPE_SET = "set";
	protected static final String KEY_TYPE_ZSET = "zset";
	protected static final String KEY_TYPE_LIST = "list";
	protected static final String KEY_TYPE_HASH = "hash";
	
	//TreeView树邮件菜单
	protected static final MenuItem refreshItem = new MenuItem("刷新");
	protected static final MenuItem disconnectItem = new MenuItem("断开连接");
	protected static final MenuItem clearDBItem = new MenuItem("清理DB");
	protected static final MenuItem createKeyItem = new MenuItem("创建键");
	protected static final MenuItem delKeyItem = new MenuItem("删除键");
	protected static final MenuItem expireItem = new MenuItem("设置有效期");
	protected static final MenuItem persistItem = new MenuItem("清除有效期");
	protected static final MenuItem renameItem = new MenuItem("重命名");
	protected static final MenuItem setItem = new MenuItem("设置值");
	protected static final MenuItem saddItem = new MenuItem("增加项");
	protected static final MenuItem sremItem = new MenuItem("删除项");
	protected static final MenuItem zaddItem = new MenuItem("增加项");
	protected static final MenuItem zremItem = new MenuItem("删除项");
	protected static final MenuItem lsetItem = new MenuItem("设置元素");
	protected static final MenuItem linsertItem = new MenuItem("元素左/右插入");
	protected static final MenuItem lpushItem = new MenuItem("左侧插入");
	protected static final MenuItem lpopItem = new MenuItem("左侧弹出");
	protected static final MenuItem rpushItem = new MenuItem("右侧插入");
	protected static final MenuItem rpopItem = new MenuItem("右侧弹出");
	protected static final MenuItem lremItem = new MenuItem("移除元素");
	protected static final MenuItem hsetItem = new MenuItem("设置项");
	protected static final MenuItem hdelItem = new MenuItem("删除项");
	
	//应用日志对象
	protected Logger appLogger;
	
	//界面控制器组件对象
	protected RedisClientController controller;
	
	protected abstract void linsert(int db, String key, ListPosition where, String pivot, String value);
	
	protected abstract void rpush(int db, String key, String value);

	protected abstract void lpush(int db, String key, String value);
	
	protected abstract void lset(int db, String key, long index, String value);
	
	protected abstract void lpop(int db, String key);
	
	protected abstract void rpop(int db, String key);
	
	protected abstract void rename(int db, String key, String newName);
	
	protected abstract void srem(int db, String key, String item);

	protected abstract void zrem(int db, String key, String item);

	protected abstract void lrem(int db, String key, String item);

	protected abstract void hdel(int db, String key, String item);
	
	protected abstract void select(int i);

	protected abstract String type(int db, String key);

	protected abstract Set<String> keys(int db, String string);
	
	protected abstract String getRedisInfo();
	
	protected abstract String getDBInfo(int db);

	protected abstract Long ttl(int db, String key);

	protected abstract String get(int db, String key);

	protected abstract Set<String> smembers(int db, String key);

	protected abstract Set<Tuple> zrangeWithScores(int db, String key, int i, int j);

	protected abstract List<String> lrange(int db, String key, int i, int j);

	protected abstract Map<String,String> hgetAll(int db, String key);

	protected abstract void set(int db, String name, String value);

	protected abstract void sadd(int db, String name, String[] array);

	protected abstract void sadd(int db, String name, String value);

	protected abstract void zadd(int db, String name, Map<String, Double> data);

	protected abstract void lpush(int db, String name, String[] array);

	protected abstract void hset(int db, String name, Map<String, String> data);

	protected abstract void del(int db, String key);

	protected abstract void expire(int db, String key, int expire);

	protected abstract void persist(int db, String key);

	protected abstract void flushDB(int db);
	
	@Override
	public void init(RedisClientController controller) {
		this.controller = controller;
		this.appLogger = controller.getAppLogger();
		
		appLogger.info("初始化客户端组件！");
		this.createConnection();
	}
	
	protected abstract boolean createConnection();
	
	/**
	 * 初始化TreeView树
	 */
	protected void initTreeView() {
		appLogger.info("初始化Redis树结构。");
		TreeView<RedisTreeNode> redisTreeView = controller.getRedisTreeView();
		appLogger.info("初始化树节点！");
		TreeItem<RedisTreeNode> root = this.getRootTreeItem();
		redisTreeView.setRoot(root);
		
		appLogger.info("添加节点选择监听事件！");
		//节点选择事件处理
		redisTreeView.getSelectionModel().selectedItemProperty().addListener((observable,oldValue,newValue)->{
			appLogger.info("Redis树节点被点击 -> oldValue:"+oldValue+",newValue:"+newValue);
			TreeItem<RedisTreeNode> currentSelectedItem = (TreeItem<RedisTreeNode>) newValue;
			if(currentSelectedItem==null) return;
			
			//设置节点信息
			RedisTreeNode selectedNode = currentSelectedItem.getValue();
			String itemInfo = this.getItemInfo(selectedNode);
			controller.getInfoTextArea().setText(itemInfo);
			
			if(!selectedNode.isLeaf() && !selectedNode.isLoaded()) {
				//加载子节点
				currentSelectedItem.getChildren().addAll(this.getChildren(selectedNode));
				currentSelectedItem.setExpanded(true);
			}
			
			//标记节点已加载过
			selectedNode.setLoaded(true);
		});
		
		initRedisTreeContextMenu();
		
		appLogger.info("Redis树结构初始化完成！");
	}

	protected void initRedisTreeContextMenu() {
		appLogger.info("设置树节点右键菜单！");
		final TreeView<RedisTreeNode> redisTreeView = controller.getRedisTreeView();
		
		//设置TreeView树右键菜单
		refreshItem.setOnAction((event)->{
			appLogger.info("执行[刷新]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
			}else {
				selectedItem.getChildren().clear();
				selectedItem.getChildren().addAll(this.getChildren(redisTreeNode));
				selectedItem.setExpanded(true);
			}
		});
		
		disconnectItem.setOnAction((event)->{
			appLogger.info("执行[断开连接]动作！");
			try {
				this.close();
				controller.getRedisTreeView().setRoot(null);
				controller.getRedisTreeView().setContextMenu(null);
				controller.getInfoTextArea().clear();
				controller.getCmdTextArea().setText("连接已断开！\n");
			} catch (IOException e) {
				AlertUtil.exception(e);
			}
			
		});
		
		clearDBItem.setOnAction((event)->{
			appLogger.info("执行[清理DB]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisDBTreeNode) {
				int db = ((RedisDBTreeNode) redisTreeNode).getDb();
				this.flushDB(db);
				selectedItem.getChildren().clear();
			}
		});
		
		createKeyItem.setOnAction((event)->{
			appLogger.info("执行[创建键]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisDBTreeNode) {
				int db = ((RedisDBTreeNode) redisTreeNode).getDb();
				try {
					ComboBox<String> typeComboBox = new ComboBox<String>(FXCollections.observableArrayList(
							KEY_TYPE_STRING,KEY_TYPE_SET,KEY_TYPE_ZSET,KEY_TYPE_LIST,KEY_TYPE_HASH));
					typeComboBox.getSelectionModel().select(KEY_TYPE_STRING);
					TextField nameTextField = new TextField();
					TextField expireTextField = new TextField();
					TextArea valueTextArea = new TextArea();
					FormDialog createKeyDialog = new FormDialog("创建键",
							new FormDialog.Item("类型：", typeComboBox),
							new FormDialog.Item("键名：", nameTextField),
							new FormDialog.Item("过期时间(秒)：", expireTextField),
							new FormDialog.Item("值(非字符串结构用json表示)：", valueTextArea));
					Optional<Boolean> result = createKeyDialog.showAndWait();
					if(result.isPresent()) {
						String type = typeComboBox.getValue();
						String name = nameTextField.getText();
						String value = valueTextArea.getText();
						String expire = expireTextField.getText();
						if(KEY_TYPE_STRING.equals(type)) {
							this.set(db,name, value);
						}else if(KEY_TYPE_SET.equals(type)) {
							try {
								if(JSONValidator.from(value).validate()){
									JSONArray data = JSON.parseArray(value);
									this.sadd(db,name, data.toArray(new String[data.size()]));
								}else {
									this.sadd(db,name, value);
								}
							} catch (Exception e) {
								//非json字符串
								this.sadd(db,name, value);
							}
						}else if(KEY_TYPE_ZSET.equals(type)) {
							this.zadd(db,name, JSON.parseObject(value,new TypeReference<Map<String,Double>>(){}));
						}else if(KEY_TYPE_LIST.equals(type)) {
							JSONArray data = JSON.parseArray(value);
							this.lpush(db,name, data.toArray(new String[data.size()]));
						}else if(KEY_TYPE_HASH.equals(type)) {
							this.hset(db,name, JSON.parseObject(value,new TypeReference<Map<String,String>>(){}));
						}
						if(expire!=null&&!"".equals(expire.trim())) {
							this.expire(db,name, Integer.valueOf(expire));
						}
						selectedItem.getChildren().add(new TreeItem<RedisTreeNode>(new RedisKeyTreeNode(db, type, name)));
					}
				} catch (Exception e) {
					AlertUtil.exception(e);
				}
			}
		});
		
		delKeyItem.setOnAction((event)->{
			appLogger.info("执行[删除键]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				this.del(db,key);
				
				selectedItem.getParent().getChildren().remove(selectedItem);
			}
		});
		
		expireItem.setOnAction((event)->{
			appLogger.info("执行[设置有效期]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("设置有效期","请在下方输入框内输入新的有效期(单位：秒)：");
				if(result.isPresent()) {
					int expire = Integer.parseInt(result.get());
					this.expire(db,key,expire);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		persistItem.setOnAction((event)->{
			appLogger.info("执行[清除有效期]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				this.persist(db,key);
				//更新节点信息
				this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
			}
		});		
		
		renameItem.setOnAction((event)->{
			appLogger.info("执行[重命名]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("重命名", "请输入键的新名称！");
				if(result.isPresent()) {
					String newName = result.get();
					this.rename(db,key,newName);
					TreeItem<RedisTreeNode> parentItem = selectedItem.getParent();
					parentItem.getChildren().remove(selectedItem);
					parentItem.getChildren().add(selectedItem);
					((RedisKeyTreeNode) redisTreeNode).setKey(newName);
				}
			}
		});
		
		setItem.setOnAction((event)->{
			appLogger.info("执行[设置值]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextArea valueTextArea = new TextArea(this.get(db,key));
				FormDialog formDialog = new FormDialog("设置值",new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					String newValue = valueTextArea.getText();
					this.set(db, key, newValue);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		saddItem.setOnAction((event)->{
			appLogger.info("执行[增加项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextArea valueTextArea = new TextArea();
				FormDialog formDialog = new FormDialog("增加项",new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					String value = valueTextArea.getText();
					this.sadd(db, key, value);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		sremItem.setOnAction((event)->{
			appLogger.info("执行[删除项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("删除项", "请输入删除项名称！");
				if(result.isPresent()) {
					this.srem(db,key,result.get());
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		zaddItem.setOnAction((event)->{
			appLogger.info("执行[增加项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextField scoreTextField = new TextField();
				TextArea valueTextArea = new TextArea();
				FormDialog formDialog = new FormDialog("增加项",
						new FormDialog.Item("分数:", scoreTextField),
						new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					Double score = Double.parseDouble(scoreTextField.getText());
					String value = valueTextArea.getText();
					Map<String,Double> data = new HashMap<>(1);
					data.put(value, score);
					this.zadd(db, key, data);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		zremItem.setOnAction((event)->{
			appLogger.info("执行[删除项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("删除项", "请输入删除项名称！");
				if(result.isPresent()) {
					this.zrem(db,key,result.get());
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		lsetItem.setOnAction((event)->{
			appLogger.info("执行[设置元素]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextField indexTextField = new TextField();
				TextArea valueTextArea = new TextArea();
				FormDialog formDialog = new FormDialog("设置元素",
						new FormDialog.Item("位置:", indexTextField),
						new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					long index = Long.parseLong(indexTextField.getText());
					String value = valueTextArea.getText();
					this.lset(db,key,index,value);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		linsertItem.setOnAction((event)->{
			appLogger.info("执行[元素左/右插入]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				String before = "左侧";
				String after = "右侧";
				TextField refItemTextField = new TextField();
				ComboBox<String> posComboBox = new ComboBox<>(FXCollections.observableArrayList(Arrays.asList(before,after)));
				TextArea valueTextArea = new TextArea();
				FormDialog formDialog = new FormDialog("元素左/右插入",
						new FormDialog.Item("参考元素:", refItemTextField),
						new FormDialog.Item("相对位置:", posComboBox),
						new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();
				if(result.isPresent()) {
					ListPosition where = null;
					if(before.equals(posComboBox.getValue())){
						where = ListPosition.BEFORE;
					}else if(after.equals(posComboBox.getValue())) {
						where = ListPosition.AFTER;
					}
					String pivot = refItemTextField.getText();
					String value = valueTextArea.getText();
					this.linsert(db, key, where, pivot, value);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		lpushItem.setOnAction((event)->{
			appLogger.info("执行[左侧插入]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextArea valueTextArea = new TextArea(this.get(db,key));
				FormDialog formDialog = new FormDialog("左侧插入",new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					String value = valueTextArea.getText();
					this.lpush(db,key,value);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		lpopItem.setOnAction((event)->{
			appLogger.info("执行[左侧弹出]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				this.lpop(db,key);
				//更新节点信息
				this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
			}
		});
		
		rpushItem.setOnAction((event)->{
			appLogger.info("执行[右侧插入]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextArea valueTextArea = new TextArea(this.get(db,key));
				FormDialog formDialog = new FormDialog("右侧插入",new FormDialog.Item("值:", valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();	
				if(result.isPresent()) {
					String value = valueTextArea.getText();
					this.rpush(db,key,value);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		rpopItem.setOnAction((event)->{
			appLogger.info("执行[右侧弹出]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				this.rpop(db,key);
				//更新节点信息
				this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
			}
		});
		
		lremItem.setOnAction((event)->{
			appLogger.info("执行[移除元素]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("删除项", "请输入移除元素名称！");
				if(result.isPresent()) {
					this.lrem(db,key,result.get());
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		hsetItem.setOnAction((event)->{
			appLogger.info("执行[设置项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				TextField itemTextField = new TextField();
				TextArea valueTextArea = new TextArea();
				FormDialog formDialog = new FormDialog("设置项",
						new FormDialog.Item("项:", itemTextField),
						new FormDialog.Item("值:",valueTextArea));
				Optional<Boolean> result = formDialog.showAndWait();
				if(result.isPresent()) {
					String item = itemTextField.getText();
					String value = itemTextField.getText();
					Map<String,String> data = new HashMap<>();
					data.put(item, value);
					this.hset(db, key, data);
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));	
				}
			}
		});
		
		hdelItem.setOnAction((event)->{
			appLogger.info("执行[删除项]动作！");
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisKeyTreeNode) {
				int db = ((RedisKeyTreeNode) redisTreeNode).getDb();
				String key = ((RedisKeyTreeNode) redisTreeNode).getKey();
				Optional<String> result = AlertUtil.input("删除项", "请输入移除元素名称！");
				if(result.isPresent()) {
					this.hdel(db,key,result.get());
					//更新节点信息
					this.controller.getInfoTextArea().setText(getItemInfo(redisTreeNode));
				}
			}
		});
		
		redisTreeView.setContextMenu(new ContextMenu(disconnectItem)); 
		redisTreeView.setOnContextMenuRequested((event)->{
			redisTreeView.getContextMenu().getItems().clear();
			redisTreeView.getContextMenu().getItems().add(refreshItem);
			TreeItem<RedisTreeNode> selectedItem = redisTreeView.getSelectionModel().getSelectedItem();
			RedisTreeNode redisTreeNode = selectedItem.getValue();
			if(redisTreeNode instanceof RedisRootTreeNode) {
				redisTreeView.getContextMenu().getItems().add(disconnectItem);
			}else if(redisTreeNode instanceof RedisDBTreeNode) {
				redisTreeView.getContextMenu().getItems().addAll(createKeyItem,clearDBItem);
			}else if(redisTreeNode instanceof RedisKeyTreeNode) {
				String type = ((RedisKeyTreeNode) redisTreeNode).getType();
				if(KEY_TYPE_STRING.equals(type)) {
					redisTreeView.getContextMenu().getItems().addAll(setItem);
				}else if(KEY_TYPE_SET.equals(type)){
					redisTreeView.getContextMenu().getItems().addAll(saddItem,sremItem);
				}else if(KEY_TYPE_ZSET.equals(type)) {
					redisTreeView.getContextMenu().getItems().addAll(zaddItem,zremItem);
				}else if(KEY_TYPE_LIST.equals(type)) {
					redisTreeView.getContextMenu().getItems().addAll(lsetItem,linsertItem,lpushItem,lpopItem,rpushItem,rpopItem,lremItem);
				}else if(KEY_TYPE_HASH.equals(type)) {
					redisTreeView.getContextMenu().getItems().addAll(hsetItem,hdelItem);
				}
				redisTreeView.getContextMenu().getItems().addAll(renameItem,expireItem,persistItem,delKeyItem);
			}
		});
	};

	/**
	 * 获取根节点
	 * @return　根节点对象
	 */
	protected abstract TreeItem<RedisTreeNode> getRootTreeItem();

	/**
	 * 获取根节点
	 * @return　根节点对象
	 */
	protected TreeItem<RedisTreeNode> getRootTreeItem(String connStr) {
		appLogger.info("获取Redis树根节点！");
		RedisRootTreeNode rootNode = new RedisRootTreeNode(connStr);
		TreeItem<RedisTreeNode> rootItem = new TreeItem<RedisTreeNode>(rootNode);
		rootItem.setExpanded(true);
		rootItem.getChildren().addAll(this.getChildren(rootNode));
		return rootItem;
	}

	/**
	 * 获取子节点集合
	 * @param selectedNode　当前选中节点
	 * @return　子节点集合
	 */
	protected List<TreeItem<RedisTreeNode>> getChildren(RedisTreeNode selectedNode) {
		appLogger.info("获取Redis树子节点！当前节点："+selectedNode);
		if(selectedNode instanceof RedisRootTreeNode) {
			List<TreeItem<RedisTreeNode>> dbNodeList = new ArrayList<>();
			for(int i=0;i<Integer.MAX_VALUE;i++) {
				try {
					this.select(i);
				} catch (Exception e) {
					break;
				}
				RedisDBTreeNode dbNode = new RedisDBTreeNode(i);
				TreeItem<RedisTreeNode> dbItem = new TreeItem<RedisTreeNode>(dbNode);
				dbNodeList.add(dbItem);
			}
			return dbNodeList;
		}else if(selectedNode instanceof RedisDBTreeNode) {
			RedisDBTreeNode dbRedisTreeNode = (RedisDBTreeNode)selectedNode;
			int db = dbRedisTreeNode.getDb();
			Set<String> keys=this.keys(db,"*");
			List<TreeItem<RedisTreeNode>> keyNodeList = new ArrayList<>();
			for(String key:keys) {
				String type = this.type(db,key);
				RedisKeyTreeNode keyNode = new RedisKeyTreeNode(db, type, key);
				TreeItem<RedisTreeNode> keyItem = new TreeItem<RedisTreeNode>(keyNode);
				keyNodeList.add(keyItem);
			}
			return keyNodeList;
		}
		return null;
	}

	/**
	 * 获取节点信息
	 * @param selectedNode　当前选中节点
	 * @return　节点信息
	 */
	protected String getItemInfo(RedisTreeNode selectedNode) {
		appLogger.info("获取Redis树节点详情信息。当前节点："+selectedNode);
		if(selectedNode instanceof RedisRootTreeNode) {
			return this.getRedisInfo();
		}else if(selectedNode instanceof RedisDBTreeNode) {
			RedisDBTreeNode dbNode = (RedisDBTreeNode)selectedNode;
			int db = dbNode.getDb();
			return this.getDBInfo(db);
		}else if(selectedNode instanceof RedisKeyTreeNode) {
			RedisKeyTreeNode keyNode = (RedisKeyTreeNode)selectedNode;
			int db = keyNode.getDb();
			String type = keyNode.getType();
			String key = keyNode.getKey();
			Long ttl = this.ttl(db,key);
			StringBuilder keyInfo = new StringBuilder();
			keyInfo.append("TYPE: "+type+"\tTTL: "+ttl+"\n");
			keyInfo.append("------------------------------------------------------------\n");
			if(KEY_TYPE_STRING.equalsIgnoreCase(type)) {
				keyInfo.append(this.get(db,key));
			}else if(KEY_TYPE_SET.equalsIgnoreCase(type)) {
				keyInfo.append(JSON.toJSONString(this.smembers(db,key), true));
			}else if(KEY_TYPE_ZSET.equalsIgnoreCase(type)){
				Map<String,Double> zsetReuslt = new HashMap<String, Double>();
				for(Tuple item:this.zrangeWithScores(db,key, 0, -1)) {
					zsetReuslt.put(item.getElement(), item.getScore());
				}
				keyInfo.append(JSON.toJSONString(zsetReuslt, true));
			}else if(KEY_TYPE_LIST.equalsIgnoreCase(type)) {
				keyInfo.append(JSON.toJSONString(this.lrange(db,key, 0, -1), true));
			}else if(KEY_TYPE_HASH.equalsIgnoreCase(type)) {
				keyInfo.append(JSON.toJSONString(this.hgetAll(db,key), true));
			}
			return keyInfo.toString();
		}
		return null;
	}
}
